package scales.utils.resources

trait IsClosed {
  def isClosed : Boolean
}

/**
 * Mostly exists for pulling but it is general
 * 
 * We want to enable bracketing and a more orderly shutdown of resources from the input streams.
 * Whilst the resource is closed automatically its not very helpful if you don't want to close it.
 * Due to Sun bug: 6539065 we have to wrap the actual close.  This allows us to decide IF we want to close.
 *
 * So we cover three use cases here:
 * * Enumeratees can bracket, if so desired
 * * Streams of xml can be continuously plied for more xml messages
 * * Users who want to manually close early can do so too.
 *
 * As a note this fits very closely to the scala-arm stuff, which I happily use in another project.  But it has
 * two specific seperate use cases:
 * * XmlPulls should be joinable as iterators ++ should ensure that the resources are closed
 * * Additionally, however, closing on the resulting XmlPull should close the lot.
 * 
 * So we either override the ++ to behave differently or we abstract away using of the stream from closing it.
 *
 */ 
trait CloseOnNeed extends IsClosed { 
  parent =>

  protected def doClose : Unit 

  private[utils] var closed = false

  def isClosed = closed

  /**
   * Close the underlying something, but only do it once.
   *
   * This allows closing of an xml input stream directly after the end doc, but without disturbing
   * the normal model.
   */ 
  def closeResource =
    if (!closed) {
      closed = true;
      doClose
    } else ()
  
  def ++( close2 : CloseOnNeed ) : CloseOnNeed = new CloseOnNeed {
    added =>
  
    def doClose = ()
     
    override def closeResource = 
      if (!closed) {
	closed = true;
	parent.closeResource
	close2.closeResource
      } else ()

    // flip it back to stop from endlessly repeating ourselves

    override def ++(close3 : CloseOnNeed) = {
      close3 ++ this
    }
  }
}

/**
 * Simple pool interface
 */ 
trait Pool[T] {
  def grab : T 

  def giveBack( t : T ) : Unit
}

/**
 * Thread safe unbounded pool, if more objects are required it will simple create them.  The optional parameter reduceSize tries to help clean up a bit when an excessive amount is created but does not act as a semaphore
 */ 
trait SimpleUnboundedPool[T] extends Pool[T] with Loaner[T] with Creator[T] {
  val reduceSize : Int = 30
  
  val size = new java.util.concurrent.atomic.AtomicInteger(0)

  private[this] val cache = new java.util.concurrent.ConcurrentLinkedQueue[T]();

  def grab = {
    val res = cache.poll
    if (res != null) res
    else doCreate
  }

  def giveBack( t : T ) {
    if (size.get > reduceSize) size.decrementAndGet
    else cache.add(t)
  }

  final def doCreate = {
    size.getAndIncrement()
    create
  }

  /**
   * Performs a loan for you
   */ 
  def loan[X]( tThunk : T => X ) : X = {
    var t = null.asInstanceOf[T]
    try {
      t = grab // can throw

      tThunk(t)
    } finally {
      if (t != null) giveBack(t)
    }
  }

}

trait Loaner[T] {
  
  /**
   * Performs a loan for you
   */ 
  def loan[X]( tThunk : T => X ) : X 
}

/**
 * Simple factory interface
 */ 
trait Creator[T] {
  def create : T
}